package cc.jq1024.infrastructure.persistent.repository;

import cc.jq1024.domain.rebate.model.aggregate.BehaviorRebateAggregate;
import cc.jq1024.domain.rebate.model.entity.BehaviorRebateOrderEntity;
import cc.jq1024.domain.rebate.model.entity.BehaviorRebateTaskEntity;
import cc.jq1024.domain.rebate.model.valobj.BehaviorTypeVO;
import cc.jq1024.domain.rebate.model.valobj.DailyBehaviorRebateVO;
import cc.jq1024.domain.rebate.repository.IBehaviorRebateRepository;
import cc.jq1024.infrastructure.event.EventPublisher;
import cc.jq1024.infrastructure.persistent.dao.IDailyBehaviorRebateDao;
import cc.jq1024.infrastructure.persistent.dao.ITaskDao;
import cc.jq1024.infrastructure.persistent.dao.IUserBehaviorRebateOrderDao;
import cc.jq1024.infrastructure.persistent.po.DailyBehaviorRebatePO;
import cc.jq1024.infrastructure.persistent.po.TaskPO;
import cc.jq1024.infrastructure.persistent.po.UserBehaviorRebateOrderPO;
import cc.jq1024.router.strategy.IDBRouterStrategy;
import cc.jq1024.types.enums.ResponseCode;
import cc.jq1024.types.exception.AppException;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Author: jia-qiang ljq1024.cc
 * @desc: 用户返利仓储实现类
 * @Date: 2024-06-29-23:41
 */
@Slf4j
@Repository
@AllArgsConstructor
public class BehaviorRebateRepository implements IBehaviorRebateRepository {

    private final IDailyBehaviorRebateDao dailyBehaviorRebateDao;
    private final IUserBehaviorRebateOrderDao userBehaviorRebateOrderDao;
    private final ITaskDao taskDao;
    private final IDBRouterStrategy dbRouter;
    private final TransactionTemplate transactionTemplate;
    private final EventPublisher eventPublisher;
    private final ThreadPoolExecutor threadPoolExecutor;

    /**
     * 存储聚合对象数据
     *
     * @param userId                   用户ID - DbRouter分片键
     * @param behaviorRebateAggregates 行为返利聚合对象 - 集合
     */
    @Override
    public void saveUserRebateRecord(String userId, List<BehaviorRebateAggregate> behaviorRebateAggregates) {
        try {
            // 切分库表
            dbRouter.doRouter(userId);
            // 事务性编程
            transactionTemplate.execute(status -> {
                try {
                    int result = 0;
                    for (BehaviorRebateAggregate behaviorRebateAggregate : behaviorRebateAggregates) {
                        // 获取返利订单信息
                        BehaviorRebateOrderEntity behaviorRebateOrderEntity = behaviorRebateAggregate.getBehaviorRebateOrderEntity();
                        // 转为 PO 对象，操作数据库
                        UserBehaviorRebateOrderPO userBehaviorRebateOrderPO = UserBehaviorRebateOrderPO.builder()
                                .userId(behaviorRebateOrderEntity.getUserId())
                                .orderId(behaviorRebateOrderEntity.getOrderId())
                                .behaviorType(behaviorRebateOrderEntity.getBehaviorType())
                                .rebateDesc(behaviorRebateOrderEntity.getRebateDesc())
                                .rebateType(behaviorRebateOrderEntity.getRebateType())
                                .rebateConfig(behaviorRebateOrderEntity.getRebateConfig())
                                .outBusinessNo(behaviorRebateOrderEntity.getOutBusinessNo())
                                .bizId(behaviorRebateOrderEntity.getBizId())
                                .build();
                        userBehaviorRebateOrderDao.insertOne(userBehaviorRebateOrderPO);

                        // 获取任务对象
                        BehaviorRebateTaskEntity taskEntity = behaviorRebateAggregate.getTaskEntity();
                        // 转为 PO 对象，操作数据库
                        TaskPO taskPO = TaskPO.builder()
                                .userId(taskEntity.getUserId())
                                .topic(taskEntity.getTopic())
                                .messageId(taskEntity.getMessageId())
                                .message(JSON.toJSONString(taskEntity.getMessage()))
                                .state(taskEntity.getState().getCode())
                                .build();
                        taskDao.insertOne(taskPO);

                        result++;
                    }
                    return result == behaviorRebateAggregates.size() ? 1 : 0;
                } catch (DuplicateKeyException e) {
                    // 捕获唯一索引冲突异常
                    status.setRollbackOnly(); // 回滚
                    log.error("写入返利记录，唯一索引冲突 userId: {}", userId, e);
                    throw new AppException(ResponseCode.INDEX_DUP.getCode(), e);
                }
            });
        } finally {
            dbRouter.clear();
        }

        // 异步发送MQ消息
        threadPoolExecutor.execute(() -> {
            for (BehaviorRebateAggregate behaviorRebateAggregate : behaviorRebateAggregates) {
                log.info("kkk: {}", JSON.toJSONString(behaviorRebateAggregate));
                BehaviorRebateTaskEntity taskEntity = behaviorRebateAggregate.getTaskEntity();
                TaskPO task = new TaskPO();
                task.setUserId(taskEntity.getUserId());
                task.setMessageId(taskEntity.getMessageId());
                try {
                    // 发送消息【在事务外执行，如果失败还有任务补偿】
                    eventPublisher.publish(taskEntity.getTopic(), taskEntity.getMessage());
                    // 更新数据库记录，task 任务表
                    taskDao.updateTaskSendMessageCompleted(task);
                } catch (Exception e) {
                    log.error("写入返利记录，发送MQ消息失败 userId: {} topic: {}", userId, task.getTopic());
                    taskDao.updateTaskSendMessageFail(task);
                }
            }
        });
    }

    /**
     * 查询返利配置
     *
     * @param behaviorTypeVO 行为类型 - 枚举
     * @return 返利配置的集合
     */
    @Override
    public List<DailyBehaviorRebateVO> queryDailyBehaviorRebateConfig(BehaviorTypeVO behaviorTypeVO) {
        List<DailyBehaviorRebatePO> dailyBehaviorRebates = dailyBehaviorRebateDao.queryDailyBehaviorRebateByBehaviorType(behaviorTypeVO.getCode());
        if (null == dailyBehaviorRebates || dailyBehaviorRebates.isEmpty()) return Collections.emptyList();
        List<DailyBehaviorRebateVO> dailyBehaviorRebateVOS = new ArrayList<>(dailyBehaviorRebates.size());
        // 类型转换
        for (DailyBehaviorRebatePO dailyBehaviorRebate : dailyBehaviorRebates) {
            dailyBehaviorRebateVOS.add(DailyBehaviorRebateVO.builder()
                    .behaviorType(dailyBehaviorRebate.getBehaviorType())
                    .rebateDesc(dailyBehaviorRebate.getRebateDesc())
                    .rebateType(dailyBehaviorRebate.getRebateType())
                    .rebateConfig(dailyBehaviorRebate.getRebateConfig())
                    .build());
        }
        return dailyBehaviorRebateVOS;
    }

    /**
     * 根据外部单号查询订单
     *
     * @param userId        用户ID
     * @param outBusinessNo 业务ID；签到则是日期字符串，支付则是外部的业务ID
     * @return 返利订单实体
     */
    @Override
    public List<BehaviorRebateOrderEntity> queryOrderByOutBusinessNo(String userId, String outBusinessNo) {
        // 1. 参数准备
        UserBehaviorRebateOrderPO userBehaviorRebateOrderPO = UserBehaviorRebateOrderPO.builder()
                .userId(userId)
                .outBusinessNo(outBusinessNo)
                .build();
        // 2. 查询数据库
        List<UserBehaviorRebateOrderPO> userBehaviorRebateOrderPOS = userBehaviorRebateOrderDao.queryOrderByOutBusinessNo(userBehaviorRebateOrderPO);
        if (null == userBehaviorRebateOrderPOS || userBehaviorRebateOrderPOS.isEmpty()) return Collections.emptyList();
        // 3. 类型转换
        List<BehaviorRebateOrderEntity> behaviorRebateOrderEntities = new ArrayList<>(userBehaviorRebateOrderPOS.size());
        for (UserBehaviorRebateOrderPO behaviorRebateOrderPO : userBehaviorRebateOrderPOS) {
            BehaviorRebateOrderEntity behaviorRebateOrderEntity = BehaviorRebateOrderEntity.builder()
                        .userId(behaviorRebateOrderPO.getUserId())
                        .orderId(behaviorRebateOrderPO.getOrderId())
                        .behaviorType(behaviorRebateOrderPO.getBehaviorType())
                        .rebateDesc(behaviorRebateOrderPO.getRebateDesc())
                        .rebateType(behaviorRebateOrderPO.getRebateType())
                        .rebateConfig(behaviorRebateOrderPO.getRebateConfig())
                        .bizId(behaviorRebateOrderPO.getBizId())
                        .outBusinessNo(behaviorRebateOrderPO.getOutBusinessNo())
                        .build();
            behaviorRebateOrderEntities.add(behaviorRebateOrderEntity);
        }
        // 4. 返回结果
        return behaviorRebateOrderEntities;
    }
}
